PostgreSQL 全文搜索 简介

1 背景知识

全文搜索 是指从文档集合中找到匹配 查询 的文档,并可以根据与 查询相似性 顺序排序。

  1. 查询 是一组 词位操作符 的表达式。
  2. 相似性查询 在文档中出现的频率。出现的频率越高则 相似度 越高。
  3. 下图为全文搜索的整体流程:
Documents
Documents
结果集
相似度进行
排序
结果集相似度进行排序...
加快查询
加快查询
全文搜索
全文搜索
tsquery
tsquery
预处理过程(
预处理过程(
标记记号
标记记号
词典控制
词典控制
生成词位
生成词位
Table
1
1
Value 1
Value 1
2
2
Value 2
Value 2
3
3
Value 3
Value 3
tsvector
tsvector
SELECT 
SELECT 
i
i
Full Text Index
Full Text Index
Text is not SVG - cannot display

2 什么是一个文档?

文档对于文件系统,是一篇杂志文章或电子邮件消息。文档对于PostgreSQL数据库而言是指(一个或多个)表的文本字段。下面就是从 PostgreSQL 数据库多个拼接成的一个文档。

SELECT title || ' ' ||  author || ' ' ||  abstract || ' ' || body AS document
FROM messages
WHERE mid = 12;

SELECT m.title || ' ' || m.author || ' ' || m.abstract || ' ' || d.body AS document
FROM messages m, docs d
WHERE m.mid = d.did AND m.mid = 12;

3 正则表达式

PostgreSQL 对文本数据类型提供了 ~~*LIKEILIKE 正则表达式操作符,但在日常使用中无法满足自然语言的搜索需求,有下列三个原因。

3.1 问题一:派生词问题

1、因为有些词可能有数千种派生词,以英语为例:satisfysatisfiessatisfaction 两种变体单词。所以有可能无法搜索到包含 satisfies 的文档。
2、虽然正则表达式可以使用 OR 来搜索多个派生形式,但是这样做很繁琐也容易出错。

statisfies
statisfies
satisfaction
satisfacti...
statisfy
statisfy
单词变体
单词变体
Text is not SVG - cannot display

3.2 问题二:相似度排序问题

因为无法按照 相似度 进行排序,所以查询结果是杂乱无章的。

3.3 问题三:性能问题

由于没有索引的支持,每次搜索将会进行全表扫描,查询效率低下。

4 全文搜索预处理过程

  1. 全文索引 对文档进行 预处理 ,并创建 全文索引 便于以后快速的搜索。
  2. 预处理的全部过程如下:

4.1 将文档解析成 记号

  1. 从文档中提取 记号
    记号 的形式:例如 数字复杂的词电子邮件地址 等,通过对 记号 进行分类,可以对不同类型的 记号 采取最优处理。
  2. 记号 进行分类。
    取决于应用程序的需求,但是对于大部分场景都可以使用一套预定义的分类。
Note

PostgreSQL使用一个 解析器 来执行这个步骤。也可以创建自定义的解析器。

4.2 词位的正规化

此步骤将 记号 转换成 词位 。由于单词的有许多不同变体,将这些单词的 词根 提取出来就称之为 正规化

  1. 记号 是文档文本的原始片段,而 词位 将会被索引和搜索使用。
  2. 记号 相同,一个 词位 是一个字符串,但是它已经被 正规化
  3. 例如:将大写字母转换成小写形式,并且涉及移除后缀(例如英语中的 ses)和前缀,只保留词根部分。
  4. 通过词位找到同一个词的变体形式,而不需要冗长地输入所有可能的变体。
  5. 此外,这个步骤不会 正规化 停用词 ,它们是那些出现频率很高的单词,对于搜索是无用的。 PostgreSQL使用 词典 来执行这个步骤。
Note

注意:PG 数据库使用 预定义配置 包含解析器词典两部分。

4.3 创建全文索引

全文索引存储正规化后的 词位 数组,它是一个有序数组。全文索引还要存储 相似似度排名 的位置信息,并按照相似度进行排序。
全文搜索可以使用 RUM 索引GIN 索引Gist 索引 来加速。

5 全文搜索数据类型

数据类型 tsvector 来存储 预处理 后的文档。数据类型 tsquery 表示需要匹配哪些 查询词

6 全文搜索的词典

标准词典允许对 记号 如何被正规化进行细粒度的控制。主要功能

7 全文搜索函数

另外还有很多文本搜索函数和操作符可以用于这些数据类型,其中最重要的是匹配操作符 @@,它在 基本文本匹配 中介绍。

8 全文搜索配置

8.1 预定义配置

  1. 预定义配置由 default_text_search_config 参数控制。
Note

这个参数可以在:全局范围、数据库范围、会话范围设置。
to_tsvector 函数有个可选地 regconfig 函数,如果未被指定。则 default_text_search_config 生效。

  1. PostgreSQL 中有多种语言的预定义配置,提供更加强大的功能。
    (1)设置停用词。
    (2)使用 预定义配置处理同义词。基于空白之外的解析。
  2. PostgreSQL中有多种语言的预定义配置,根据不同的语言提供不同的配置。
  3. 使用 \dF 命令显示所有可用的预定义配置。
testdb=# \dF
//屏幕输出:
               List of text search configurations
   Schema   |    Name    |              Description              
------------+------------+---------------------------------------
 pg_catalog | arabic     | configuration for arabic language
 pg_catalog | armenian   | configuration for armenian language
 pg_catalog | basque     | configuration for basque language
 pg_catalog | catalan    | configuration for catalan language
 pg_catalog | danish     | configuration for danish language
 pg_catalog | dutch      | configuration for dutch language
 pg_catalog | english    | configuration for english language
 pg_catalog | finnish    | configuration for finnish language
 pg_catalog | french     | configuration for french language
 pg_catalog | german     | configuration for german language
 pg_catalog | greek      | configuration for greek language
 pg_catalog | hindi      | configuration for hindi language
 pg_catalog | hungarian  | configuration for hungarian language
 pg_catalog | indonesian | configuration for indonesian language
 pg_catalog | irish      | configuration for irish language
 pg_catalog | italian    | configuration for italian language
 pg_catalog | lithuanian | configuration for lithuanian language
 pg_catalog | nepali     | configuration for nepali language
 pg_catalog | norwegian  | configuration for norwegian language
 pg_catalog | portuguese | configuration for portuguese language
 pg_catalog | romanian   | configuration for romanian language
 pg_catalog | russian    | configuration for russian language
 pg_catalog | serbian    | configuration for serbian language
 pg_catalog | simple     | simple configuration
 pg_catalog | spanish    | configuration for spanish language
 pg_catalog | swedish    | configuration for swedish language
 pg_catalog | tamil      | configuration for tamil language
 pg_catalog | turkish    | configuration for turkish language
 pg_catalog | yiddish    | configuration for yiddish language
(29 rows)

8.2 自定义配置

为了让建立自定义文本搜索配置更容易,一个自定义配置可以从更简单的数据库对象来建立。PostgreSQL的文本搜索功能提供了四类配置相关的数据库对象:

9 全文搜索操作符 @@

@@ 是一个匹配操作符,用于判断 查询 在文档中是否找到。

9.1 匹配操作符支持的形式

  1. text @@ tsquery 等价于 to_tsvector (x) @@ y
  2. text @@ text 等价于 to_tsvector(x) @@ plainto_tsquery (y) `。
tsvector @@ tsquery
tsquery  @@ tsvector
text @@ tsquery
text @@ text

9.2 匹配操作符逻辑运算符

tsquery 中,支持逻辑运算符如下:

  1. &(AND)操作符指定它的两个参数都必须出现在文档中才表示匹配
  2. |(OR)操作符指定至少一个参数必须出现。
  3. !(NOT)操作符指定它的参数不出现才能匹配。 例如,查询 fat & ! rat 匹配包含 fat 但不包含 rat 的文档。

9.3 基本文本匹配

PostgreSQL中的全文搜索基于匹配操作符 @@ ,表示 一个 tsvector(文档)匹配一个 tsquery (查询)时返回 true,表示能够匹配成功。

SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector @@ 'cat & rat'::tsquery;
//屏幕输出:
 ?column?
----------
 t

匹配操作符 @@ 对于顺序不敏感。

SELECT 'fat & cow'::tsquery @@ 'a fat cat sat on a mat and ate a fat rat'::tsvector;
//屏幕输出:
 ?column?
----------
 f

9.4 预处理函数 to_tsvector

1 背景知识

全文搜索排序和去重是在输入文本期间自动完成的,因为要实现 全文搜索 必须从文档创建 tsvector 数据类型以及创建 tsquery 的查询。

PostgreSQL提供了函数 to_tsvector将一个文档转换成tsvector数据类型。

SELECT to_tsvector('fat cats ate fat rats') @@ to_tsquery('fat & rat');
//屏幕输出:
 ?column? 
----------
 t

9.5 不匹配的情况

由于 ::tsvector 操作符表示文本已经是正规化好的词位,所以这里不会发生词 rats 的正规化,所以 rats 不匹配 rat

SELECT 'fat cats ate fat rats'::tsvector @@ to_tsquery('fat & rat');
//屏幕输出:
 ?column? 
----------
 f